#include <pthread.h>
#include "CircleQueue.hpp"
#include <semaphore.h>

//存在并发访问问题！

template<class T>
class CPThread
{
public:
    CPThread(int n)
        :_cp(CircleQueue<T>(n))
    {
        sem_init(&_prod,0,n); //生产者一开始有五个位置可以生产
        sem_init(&_cons,0,0); //消费者一开始可以生产

        pthread_mutex_init(&_pm,nullptr);
        pthread_mutex_init(&_cm,nullptr);
    }

    void push(const T& data)
    {
        sem_wait(&_prod); //生产位置-1 如果没有生产位置则等待
        //先获取一个信号量(相当于买票) 再排队进入队列放商品 防止出现线程并发问题 两个线程向同一个位置写入数据
        pthread_mutex_lock(&_pm);
        _cp.push(data);
        pthread_mutex_unlock(&_pm);
        sem_post(&_cons); //商品+1
    }

    void pop(T& data)
    {
        sem_wait(&_cons); //商品-1 如果没有商品消费则等待
        //先获取一个信号量,再排队进入队列消费，防止两个线程消费同一个位置的资源问题(并发问题)
        pthread_mutex_lock(&_cm);
        data = _cp.front();
        _cp.pop();
        pthread_mutex_unlock(&_cm);
        sem_post(&_prod); //生产位置+1
    }

    size_t getsize() {return _cp.size();}
    

    ~CPThread()
    {
        sem_destroy(&_prod);
        sem_destroy(&_cons);

        pthread_mutex_destroy(&_pm);
        pthread_mutex_destroy(&_cm);
    }

private:
    CircleQueue<T> _cp; //循环队列
    sem_t _prod,_cons; //信号量
    pthread_mutex_t _pm,_cm; //锁
};